package cloud.hedou.abp.common

import cloud.hedou.abp.remote.HttpClient
import cloud.hedou.abp.remote.HttpClient.Companion.create
import org.springframework.amqp.rabbit.annotation.Exchange
import org.springframework.amqp.rabbit.annotation.Queue
import org.springframework.amqp.rabbit.annotation.QueueBinding
import org.springframework.amqp.rabbit.annotation.RabbitListener
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.cache.CacheManager
import org.springframework.cache.annotation.Cacheable
import org.springframework.stereotype.Repository
import retrofit2.HttpException

@Repository
class RemoteCommonService(httpClient: HttpClient) {

    private val remoteCommonApi: RemoteCommonApi = httpClient.create()

    @Autowired
    private lateinit var cacheManager: CacheManager

    @Cacheable(value = [CACHE_NAME_COMMON_CATEGORY])
    fun getCommonData(category: String): List<CommonData> {
        var response = remoteCommonApi.getCommonData(0, 100, category).execute()
        if (!response.isSuccessful) throw HttpException(response)
        val pagedList = response.body()!!
        val mutableList = pagedList.items.toMutableList()
        for (skip in 100..pagedList.totalCount step 100) {
            response = remoteCommonApi.getCommonData(skip, 100, category).execute()
            if (!response.isSuccessful) throw HttpException(response)
            mutableList.addAll(response.body()!!.items)
        }
        return flat(mutableList)
    }

    @Cacheable(value = [CACHE_NAME_COMMON_VALUE])
    fun getCommonDataByValue(category: String, value: String): CommonData? {
        return getCommonData(category)
            .find {
                it.value == value
            }
    }

    @Cacheable(value = [CACHE_NAME_COMMON_ID])
    fun getCommonDataById(id: String): CommonData {
        val response = remoteCommonApi.getCommonDataById(id).execute()
        if (!response.isSuccessful) throw HttpException(response)
        return response.body()!!
    }

    @RabbitListener(
        bindings = [
            QueueBinding(
                value = Queue("xh_tenants_common_01"),
                exchange = Exchange("xh_tenants_eventbus"),
                key = ["Hd.Common.Abstractions.Dictionaries.DictionaryData"]
            )
        ]
    )
    fun onCommonDataChanged(value: String) {
        cacheManager.getCache(CACHE_NAME_COMMON_ID)?.clear()
        cacheManager.getCache(CACHE_NAME_COMMON_VALUE)?.clear()
        cacheManager.getCache(CACHE_NAME_COMMON_CATEGORY)?.clear()
    }

    private fun flat(options: List<CommonData>, list: MutableList<CommonData> = mutableListOf()): List<CommonData> {
        list.addAll(options)
        options.forEach {
            val children = it.children
            if (!children.isNullOrEmpty()) {
                flat(children, list)
            }
        }
        return list
    }


    companion object {
        private const val CACHE_NAME_COMMON_ID = "common-data-by-id"
        private const val CACHE_NAME_COMMON_VALUE = "common-data-by-value"
        private const val CACHE_NAME_COMMON_CATEGORY = "common-data-by-category"
    }

}